
package vplot;


import java.awt.*;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

// this class implements Matlab-like figure bookeeping 
import scalaSci.Vec;
import visad.DisplayImpl;
import visad.VisADException;
import visad.java2d.DisplayImplJ2D;
public class vfigure {
 
        static int currentPlotCnt = 0;  // a counter for the current number of figures
        static int maxNumberOfFigs = 20;  // maximum number of figure frames
        static double  figTableIncreaseFactor = 1.5; // factor to increase dynamically the figure table size
        static vPlot [] [] [] allPlots = null;  // all the plot objects that belong to each Matlab-like figure object, e.g. allPlots[f][] is the table with the references to the plots
        static public DisplayImpl  [][][] allPlotsDisplays = null;  // the displays for each plot is kept in order to add plots
        static WFrame [] allFrames =  null; // the window frames for all the frames for all the figure objects

        static public vPlot currentPlot = null;  // the "current plot object" where plot operations are directed
        static public DisplayImpl currentDisplay = null;  // // the "current display object" where plot operations are directed
        static int focusedPlotId   = -1;  // the id of the Matlab-like figure where plot operations are directed
        static int focusedSubPlotId = -1;  // the id of the subplot object where plotting operations are directed
        
        static boolean holdOnMode = true;  // controls holding previous plots, used to implement Matlab's hold("on"), hold("off")

        static int defaultXSize = 600;
        static int defaultYSize = 600;
        
    // increase the size of the global figure table when required
        private  static void  increasevFigTable() {
            int maxNumberOfFigsLarge = (int)(maxNumberOfFigs*figTableIncreaseFactor);  // update number of figs
            WFrame []  cpAllFrames = new WFrame[maxNumberOfFigsLarge];   // table that holds indices to the new figure frames
            for (int k=0; k<allFrames.length; k++)  // copy previous to enlarged
                cpAllFrames[k] = allFrames[k];
            vPlot  [][][] cpAllPlots = new vPlot[maxNumberOfFigsLarge][][];
            DisplayImpl [][][] cpAllDisplays = new DisplayImpl[maxNumberOfFigsLarge][][];
            
            for (int k=0; k<maxNumberOfFigs; k++) {// copy previous to enlarged
                cpAllPlots[k] = allPlots[k];
                cpAllDisplays[k] = allPlotsDisplays[k];
            }
            for (int k=maxNumberOfFigs; k<maxNumberOfFigsLarge; k++) {  // new entries to nulls
                cpAllPlots[k] = null;
                cpAllDisplays[k] = null;
                cpAllFrames[k] = null;
            }
            maxNumberOfFigs = maxNumberOfFigsLarge;  // update figure table size
            //   enlarged tables become the current
            allPlots = cpAllPlots;
            allPlotsDisplays = cpAllDisplays;
            allFrames = cpAllFrames;
        }

        // increase the Figure tables to cover the specified Figure number
        private  static void  increasevFigTableSpecifiedSize(int specifiedFigNo) {
            if (specifiedFigNo <= maxNumberOfFigs)
                return;  // specified size smaller than the current Figure table size
            int maxNumberOfFigsLarge = (int)(figTableIncreaseFactor*specifiedFigNo);  // update number of figs
            WFrame []  cpAllFrames = new WFrame[maxNumberOfFigsLarge];
            for (int k=0; k<allFrames.length; k++)  // copy previous to enlarged
                cpAllFrames[k] = allFrames[k];
            vPlot [][][] cpAllPlots = new vPlot[maxNumberOfFigsLarge][][];
            DisplayImpl [][][] cpAllDisplays =  new DisplayImpl[maxNumberOfFigsLarge][][];
            for (int k=0; k<maxNumberOfFigs; k++)  { // copy previous to enlarged
                cpAllPlots[k] = allPlots[k];
                cpAllDisplays[k] = allPlotsDisplays[k];
            }
            for (int k=maxNumberOfFigs; k<maxNumberOfFigsLarge; k++) {  // new entries to nulls
                cpAllPlots[k] = null;
                cpAllDisplays[k] = null;
                cpAllFrames[k] = null;
            }
            maxNumberOfFigs = maxNumberOfFigsLarge;  // update figure table size
            //   enlarged tables become the current
            allPlots = cpAllPlots;
            allPlotsDisplays = cpAllDisplays;
            allFrames = cpAllFrames;
        }


        // initializes the ploting system
	private static void initvplots() {
		if (allFrames == null)  {   // plotting system not initialized yet
                    allPlots = new vPlot[maxNumberOfFigs][][];  // all the "subplot" objects
                    allPlotsDisplays = new DisplayImpl[maxNumberOfFigs][][];
                    for (int k=0; k<maxNumberOfFigs; k++) {
                       allPlots[k] = null;
                       allPlotsDisplays[k] = null;
                    }
                   
                    allFrames = new WFrame[maxNumberOfFigs];   // all the "figure" objects
                    for (int k=0; k<maxNumberOfFigs; k++)
                        allFrames[k] = null;
                      currentPlotCnt = 0;

                    focusedPlotId   = 0;   // the id of the current figure initially
                    focusedSubPlotId = 0;
                    currentPlot = null;    // initially we do not have a current plot
                    currentDisplay = null;
                }
          }

/*
 var vp = vfigure(1)
 var t = inc(0, 0.01, 10); var x = sin(0.23*t)
 vplot(x)
 var y = sin(9.8*t) +x
 var vp2 = vfigure(2)
 vsubplot(2,1,1)
 vplot(y.getv)
 */ 

    
         // focus on the figure with the identifier figId returning the first vPlot from it
	static public vPlot  vfigure(int figId) {
          initvplots();  // init the plotting system if not initialized yet
          focusedPlotId = figId-1;  //  figure IDs start at 1 according to Matlab conventions
          if (figId < 1)  // assume the smallest figId when a zero or negative figId is requested
                figId = 1;  
          if (figId > maxNumberOfFigs)   // increase Figure table size
                increasevFigTableSpecifiedSize(figId);
                                               
          if (allPlots[focusedPlotId] != null)  {  // figure id exists
               currentPlot = allPlots[focusedPlotId][0][0];  // the requested figure panel
               currentDisplay = allPlotsDisplays[focusedPlotId][0][0];   // the currently focused display 
               
          WFrame currentFrame = allFrames[focusedPlotId];  
          currentFrame.setSize(defaultXSize, defaultYSize);
          currentFrame.setVisible(true);
          return  currentPlot;
             }
            else   {  // we do not have the requested figure object, create it explicitly
              /*WFrame currentFrame =      new WFrame(focusedPlotId, "Figure "+figId);   // create the new WFrame for the figure
              vPlot newPlot2DPanel = new vPlot(currentPlotCnt);
              allPlots[focusedPlotId] = new vPlot[1][1];  // create an initial grid of 1X1
              allPlots[focusedPlotId][0][0] = newPlot2DPanel; 
              
               */
              currentPlot = vsubplot(1, 1, 1);    // create a grid structure of subplots at this figure
              
              return currentPlot;
    }
  }   

      
     
         // create a new figure holding one vPlot object
	static public vPlot  vfigure() {
            focusedPlotId++;   // increase by one the current focused fig. id.
            int figId = focusedPlotId;   // init current Figure Id
            if (figId < 0)  // assume the smallest figId when a zero or negative figId is requested
                figId = 0;
            if (figId >= maxNumberOfFigs)   // increase Figure table size
                increasevFigTableSpecifiedSize(figId);

           vsubplot(1, 1, 1);
           return currentPlot;
          }
                
        
            // returns the current number of figure objects (e.g. FrameView objects), is the number of non-null entries of the allFrames[] table
        static   public int  getvFigCount()  {
            int figCnt=0;
            for (int k=0; k<maxNumberOfFigs; k++)
                if (allFrames[k] != null)
                    figCnt++;

            return figCnt;
        }

        
public static vPlot vsubplot( int  p)  {
    int  r = p / 100;  
    int  rem = p % 100;
    int c = rem / 10;
    int  id = rem % 10;
    return vsubplot(r, c, id);
}

       

// creates a Matlab-like placement of multiple subplots in the current Figure with index currentFigId
// returns the id of the figure object
 static public vPlot  vsubplot(int rows, int cols, int focusSubPlot)  {
         initvplots();
         if (focusedPlotId  <= -1)  {
             JOptionPane.showMessageDialog(null, "Not properly focused figure");
             return currentPlot;
         }

         if (allFrames[focusedPlotId] == null) {  // create new 2D-figure panel
                   // create new figure
                vPlot [] [] newPlot2DPanel = new vPlot[rows][cols];
                DisplayImpl [][] newDisplays = new DisplayImpl[rows][cols];
                for (int ni=0; ni<rows; ni++) {   // initialize the new plot panel
                    for (int mi=0; mi<cols; mi++) {
                        vPlot vplotObj = new vPlot(focusedPlotId);  // each vPlot keeps a reference to the figure id
                                                                                            // where it belongs
                        newPlot2DPanel[ni][mi] = vplotObj;
                    try {
                        currentDisplay = new DisplayImplJ2D("display");
                        newDisplays[ni][mi] = currentDisplay;
                    } catch (VisADException ex) {
                        Logger.getLogger(vfigure.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (RemoteException ex) {
                        Logger.getLogger(vfigure.class.getName()).log(Level.SEVERE, null, ex);
                    }

                  }
               }   // initialize the new plot panel
         
                allPlots[focusedPlotId] = newPlot2DPanel;
                allPlotsDisplays[focusedPlotId] = newDisplays;
            
                String figTitle = "vFigure "+(focusedPlotId+1);
                WFrame currentFrame = new WFrame(focusedPlotId, figTitle);
              
            
          // set-up the grid for this figure adding vPlots in its cells
                currentFrame.setLayout(new GridLayout(rows, cols)); 
                for (int ni=0; ni<rows; ni++)  {  // initialize the new plot panel
                    for (int mi=0; mi<cols; mi++)
                        currentFrame.add(allPlots[focusedPlotId][ni][mi]);   // add the subpanels corresponding to subplots
                }
  
               allPlots[focusedPlotId] = newPlot2DPanel;   // the vPlots grid of objects 
               allFrames[focusedPlotId] = currentFrame;

                
         //   focus on the requested subplot 
                int rowNo = (int)(focusSubPlot / cols);
		if (rowNo*cols == focusSubPlot)  rowNo--;

		int colNo = (int)(focusSubPlot - rowNo*cols) - 1;
                currentPlot = newPlot2DPanel[rowNo][colNo];
                
                currentFrame.setSize(defaultXSize, defaultYSize); 
                currentFrame.setVisible(true);
 
                return currentPlot;
       }
          else {  // either focus on the requested plot if the subplot grid structure matches,
                    // or otherwise create a new subplot structure
             vPlot [][] currentPlot2DPanel = (vPlot [][]) allPlots[focusedPlotId];
             vPlot [] [] newPlot2DPanel = currentPlot2DPanel;

             int yGrid = currentPlot2DPanel.length;
             int xGrid = currentPlot2DPanel[0].length;
             if (yGrid != rows || xGrid != cols)   {    // a grid of different size is requested
                 newPlot2DPanel = new vPlot[rows][cols];
                DisplayImpl [][] newDisplays = new DisplayImpl[rows][cols];

                                // create new figure
                for (int ni=0; ni<rows; ni++)   // initialize the new plot panel
                    for (int mi=0; mi<cols; mi++) {
                        vPlot vplotObj = new vPlot(focusedPlotId);  
                        newPlot2DPanel[ni][mi] = vplotObj;
                    try {
                        currentDisplay = new DisplayImplJ2D("display");
                        newDisplays[ni][mi] = currentDisplay;
                    } catch (VisADException ex) {
                        Logger.getLogger(vfigure.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (RemoteException ex) {
                        Logger.getLogger(vfigure.class.getName()).log(Level.SEVERE, null, ex);
                    }

                  }
                 allFrames[focusedPlotId].dispose();   // dispose the frame that has improper subplot configuration    
                 allPlots[focusedPlotId] = newPlot2DPanel;   // keep the new configuration of the plotting grid
                 allPlotsDisplays[focusedPlotId] = newDisplays;
                 
                 String figTitle = "vFigure "+(focusedPlotId+1);
        
                WFrame currentFrame = new WFrame(focusedPlotId, figTitle);
                currentFrame.setLayout(new GridLayout(rows, cols)); 
                for (int ni=0; ni<rows; ni++)  {  // initialize the new plot panel
                    for (int mi=0; mi<cols; mi++)
                        currentFrame.add(newPlot2DPanel[ni][mi]);   // add the subpanels corresponding to subplots
                }
                currentFrame.setSize(defaultXSize, defaultYSize); 
                currentFrame.setVisible(true);
                
                allFrames[focusedPlotId] = currentFrame;
                
             }  // a grid of different size is requested
             int rowNo = (int)(focusSubPlot / cols);
             if (rowNo*cols == focusSubPlot)  rowNo--;

             int colNo = (int)(focusSubPlot - rowNo*cols) - 1;
             currentPlot = newPlot2DPanel[rowNo][colNo];
             currentDisplay = allPlotsDisplays[focusedPlotId][rowNo][colNo];
         }

         return currentPlot;
     }

public static JPanel  vplot(double []x)  {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  
    JPanel displayPanel = currentPlot.plot(x);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
   
  }


public static JPanel  vplot(double []x, String xtitle, String ytitle,  int pointSize) {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  
    JPanel displayPanel = currentPlot.plot(x, xtitle, ytitle, pointSize);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
   
  }

public static JPanel  vplot(float []x, String xtitle, String ytitle,  int pointSize) {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  
    JPanel displayPanel = currentPlot.plot(x, xtitle, ytitle, pointSize);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
   
  }

public static JPanel  vplot(Vec x, String xtitle, String ytitle,  int pointSize) {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  
    JPanel displayPanel = currentPlot.plot(x, xtitle, ytitle, pointSize);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
   
  }

public static JPanel  vplot3(double []x)  {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  
    JPanel displayPanel = currentPlot.plot3(x, "x", "y");
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
   
  }

public static JPanel  vplot(Vec x)  {
    return vplot(x.getv());
}

public static JPanel  vaddplot(float []x)  {
  return vaddplot(x, "x", "y",  1);
}

public static JPanel  vaddplot(double []x)  {
  return vaddplot(x, "x", "y",  1);
}

public static JPanel  vaddplot(Vec x)  {
  return vaddplot(x.getv());
}

public static JPanel  vaddplot(Vec x, String xtitle, String ytitle, int pointSize)  {
    return vaddplot(x.getv(), xtitle, ytitle, pointSize);
}

public static JPanel  vaddplot(float []x, String xtitle, String ytitle, int pointSize)  {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  //currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.addplot(x,  xtitle, ytitle, pointSize);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
  }

public static JPanel  vaddplot(double []x, String xtitle, String ytitle, int pointSize)  {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  //currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.addplot(x,  xtitle, ytitle, pointSize);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
  }

public static JPanel  vplotPoint(float []x)  {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  //currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plotXPoint(x,"x", "y", 2);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
  }

public static JPanel  vplotPoint(double  []x)  {
    float [] fx = new float[x.length];
    for (int k=0; k<x.length; k++)
        fx[k] = (float) x[k];
    return vplotPoint(fx);
}

public static JPanel vplotPoint(Vec vx) {
    return vplotPoint(vx.getv());
}

// plot the array as points, i.e. without connecting lines
public static JPanel  vplotXYPoints(double []x, double []y, String xtitle, String ytitle, int pointsize)  {
 if (currentPlot == null)
      currentPlot =  vsubplot(1,1,1);  //currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plotXYPoints(x, y, xtitle, ytitle, pointsize);
    allFrames[focusedPlotId].setVisible(true);
    return displayPanel;
  }

public static JPanel  vplotXYPoints(double []x, Vec y, String xtitle, String ytitle, int pointsize)  {
    return vplotXYPoints(x, y.getv(), xtitle, ytitle, pointsize);
  }

public static JPanel  vplotXYPoints(Vec x, double [] y, String xtitle, String ytitle, int pointsize)  {
    return vplotXYPoints(x.getv(), y, xtitle, ytitle, pointsize);
  }

public static JPanel  vplotXYPoints(Vec  vx, Vec vy, String xtitle, String ytitle, int pointsize)  {
    return vplotXYPoints(vx.getv(), vy.getv(), xtitle, ytitle, pointsize);
}

public static JPanel  vplotXYPoints(float []x, float []y, String xtitle, String ytitle, int pointsize)  {
    double [] dx = new double [x.length];  double [] dy = new double[y.length];
    for (int k=0; k<x.length; k++) {      dx[k] = x[k]; dy[k] = y[k]; }
    return vplotXYPoints(dx, dy, xtitle, ytitle, pointsize);
}


// plot the array as points, i.e. without connecting lines
public static JPanel  vplotXYPoints(double []x, double []y)  {
    return vplotXYPoints(x, y, "x", "y", 1);
  }

public static JPanel  vplotXYPoints(double []x, Vec y)  {
    
    return vplotXYPoints(x, y.getv());
  }

public static JPanel  vplotXYPoints(Vec x, double [] y)   {
    return vplotXYPoints(x.getv(), y);
  }

public static JPanel  vplotXYPoints(Vec  vx, Vec vy)  {
    return vplotXYPoints(vx.getv(), vy.getv());
}

public static JPanel vplot3() {
 if (currentPlot == null)
       currentPlot = vsubplot(1,1,1);  //currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plot3();
 
    allFrames[focusedPlotId].setVisible(true);
 
    return displayPanel;
  }
 
public static JPanel  vplot(double []x, int pointSize)  {
 if (currentPlot == null)
     currentPlot = vsubplot(1,1,1);  //     currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plot(x, pointSize);
  allFrames[focusedPlotId].setVisible(true);
 
    return displayPanel;
  }
 
public static JPanel  vplot(double []x, double [] y)  {
 if (currentPlot == null)
     currentPlot = vsubplot(1,1,1);  //     currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plot(x, y);
  allFrames[focusedPlotId].setVisible(true);
 
    return displayPanel;
  }

public static JPanel  vplot(double []x, double [] y, double []z)  {
 if (currentPlot == null)
     currentPlot = vsubplot(1,1,1);  //     currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plot(x, y, z, "x", "y", "z", 1);
  allFrames[focusedPlotId].setVisible(true);
 
    return displayPanel;
  }

public static JPanel  vplot(Vec x, Vec y, Vec z)  {
    return vplot(x.getv(), y.getv(), z.getv());
}

public static JPanel  vplot(double []x, double [] y, double []z, String xtitle, String ytitle, String ztitle, int pointsize)  {
 if (currentPlot == null)
     currentPlot = vsubplot(1,1,1);  //     currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plot(x, y, z, xtitle, ytitle, ztitle, pointsize);
  allFrames[focusedPlotId].setVisible(true);
 
    return displayPanel;
  }

public static JPanel  vplot(Vec x, Vec y, Vec z, String xtitle, String ytitle, String ztitle, int pointsize)  {
    return vplot(x.getv(), y.getv(), z.getv(), xtitle, ytitle, ztitle, pointsize);
}

public static void vcloseAll() {
    for (int k=0; k<maxNumberOfFigs; k++) {
        if (allFrames[k] != null) {
            (allFrames[k]).dispose();
            allFrames[k] = null;
            allPlots[k] = null;
        }
    }
}

public static void vclose(int figId) {
       if (allFrames[figId] != null) {
            (allFrames[figId]).dispose();
            allFrames[figId] = null;
            allPlots[figId] = null;
        }
    }

public static JPanel vimage(double [][] vals) {
    if (currentPlot == null)
     currentPlot = vsubplot(1,1,1);  //     currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.image(vals, "x", "y", "z");
  allFrames[focusedPlotId].setVisible(true);
 
    return displayPanel;
  }
/* 
public static JPanel vplot(double []xvals, double []yvals, double [] zvals) {
    if (currentPlot == null)
     currentPlot = vsubplot(1,1,1);  //     currentPlot = new vPlot(0);
    JPanel displayPanel = currentPlot.plot(xvals, yvals, zvals,"x", "y", "z", 1);
  allFrames[focusedPlotId].setVisible(true);
 
    return displayPanel;
}*/

  
 }
 
    
  
